﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace GAscheduler
{
    class RulesLexer
    {
        private string m_sRules;
        private int m_iPos = 0;
        private string m_TokenStream = "";
        public ArrayList m_alRuleTokens = new ArrayList();

        /// <summary>
        /// Default constructor.
        /// </summary>
        public RulesLexer()
        { } // RulesLexer

        /// <summary>
        /// Loads the rules from the file and turns them into tokens that can be parsed. 
        ///     All tokens created this way are stored in an array m_alRuleTokens
        /// </summary>
        /// <param name="sRulesFile"></param>
        public void PopulateLexer(string sRulesFile)
        {
            m_sRules = sRulesFile; // assign data member

            while (m_TokenStream != ".") // pull out tokens as long as we haven't reached the end of the file
            {
                if (!GetNextToken())     // if we find an invalid token, stop getting tokens
                    break;

                m_alRuleTokens.Add(new RuleToken(m_TokenStream)); // otherwise keep adding them to the array
            }
        } // PopulateLexer

        /// <summary>
        /// Attempts to assign m_TokenStream with a valid token by checking for one of three things: 
        ///     if it first sees a letter, it will continue grabbing letters and/or numbers until 
        ///     it hits neither. If it instead sees a punctuation mark such as a bracket or comma, 
        ///     it will only grab that. If it sees white space, it will recursivley call itself. If
        ///     it is unable to match any of those patterns, there is an invalid token, and so the
        ///     user is alerted and false returned. For all other outcomes, true is returned.
        /// </summary>
        /// <returns></returns>
        private bool GetNextToken()
        {
            if (char.IsLetter(m_sRules[m_iPos])) // if the first char is a letter,
            {
                do
                {
                    m_TokenStream += m_sRules[m_iPos]; // read letters or numbers into the token stream until we hit white space
                    m_iPos++;
                } while (char.IsLetterOrDigit(m_sRules[m_iPos]));

                return true;                     // we should have a valid token, to return true
            }
            else if ((char)m_sRules[m_iPos] == '[' || (char)m_sRules[m_iPos] == ']' || // if the first char is a punctuation mark,
                (char)m_sRules[m_iPos] == ',' || (char)m_sRules[m_iPos] == '.')
            {
                m_TokenStream += m_sRules[m_iPos];  // only add that
                m_iPos++;

                return true;                        // any punctuation mark is a token by itself, so return true
            }
            else if (char.IsWhiteSpace(m_sRules[m_iPos])) // if the char is a white space,
            {
                m_iPos++;                                 // skip over it
                if (GetNextToken()) { return true; } else { return false; } // and try again
            }
            else // if all else fails, we have a problem, so tell the user
            {
                MessageBox.Show("Unexpected character in the rules file. Please be sure to follow the correct syntax.",
                                "Rules_Database - RulesLexer - GetNextToken", 
                                MessageBoxButtons.OK, 
                                MessageBoxIcon.Exclamation);
                return false; // the token is bad, so return false
            }
        } // GetNextToken
    }
}
